/**
 * Copyright (c) 2008 - TheNittyGritty - Thomas Brekelmans
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package nl.thenittygritty.utils 
{

	/**
	 * DateUtils is a library class which shouldn't be instantiated. Instead it
	 * provides static methods which help in working with Dates.
	 */
	public class DateUtils 
	{
		public static const MILLISECOND:int = 1;
		public static const SECOND:int = MILLISECOND * 1000;
		public static const MINUTE:int = SECOND * 60;
		public static const HOUR:int = MINUTE * 60;
		public static const DAY:int = HOUR * 24;
		public static const WEEK:int = DAY * 7;
		
		/**
		 * Private constructor for the DateUtils, this shouldn't be called.
		 */
		public function DateUtils() 
		{
			// Throw an error here, we shouldn't try to instantiate DateUtils.
			throw new Error("The DateUtils shouldn't be instantiated.");
		}
		
		/**
		 * Returns a new date containing the elapsed date between 
		 * two given dates.
		 * 
		 * @param dateA The first date object, which should be "before" dateB.		 * @param dateB The second date object, which should be "after" dateA.
		 */
		public static function elapsedDate(dateA:Date, dateB:Date):Date
		{
			return new Date(dateB.getTime() - dateA.getTime());	
		}

		/**
		 * Returns the elapsed milliseconds between two given dates.
		 * 
		 * @param dateA The first date object, which should be "before" dateB.
		 * @param dateB The second date object, which should be "after" dateA.
		 */
		public static function elapsedMilliseconds(dateA:Date, 
												   dateB:Date):Number 
		{
			return (dateB.getTime() - dateA.getTime());
		}

		/**
		 * Returns the elapsed seconds between two given dates.
		 * 
		 * @param dateA The first date object, which should be "before" dateB.
		 * @param dateB The second date object, which should be "after" dateA.
		 */
		public static function elapsedSeconds(dateA:Date, dateB:Date):Number 
		{
			return Math.floor(elapsedMilliseconds(dateA, dateB) / SECOND);
		}

		/**
		 * Returns the elapsed minutes between two given dates.
		 * 
		 * @param dateA The first date object, which should be "before" dateB.
		 * @param dateB The second date object, which should be "after" dateA.
		 */
		public static function elapsedMinutes(dateA:Date, dateB:Date):Number 
		{
			return Math.floor(elapsedMilliseconds(dateA, dateB) / MINUTE);
		}

		/**
		 * Returns the elapsed hours between two given dates.
		 * 
		 * @param dateA The first date object, which should be "before" dateB.
		 * @param dateB The second date object, which should be "after" dateA.
		 */
		public static function elapsedHours(dateA:Date, dateB:Date):Number 
		{
			return Math.floor(elapsedMilliseconds(dateA, dateB) / HOUR);
		}

		/**
		 * Returns the elapsed days between two given dates.
		 * 
		 * @param dateA The first date object, which should be "before" dateB.
		 * @param dateB The second date object, which should be "after" dateA.
		 */
		public static function elapsedDays(dateA:Date, dateB:Date):Number 
		{
			return Math.floor(elapsedMilliseconds(dateA, dateB) / DAY);
		}

		/**
		 * Returns the elapsed months between two given dates.
		 * 
		 * @param dateA The first date object, which should be "before" dateB.
		 * @param dateB The second date object, which should be "after" dateA.
		 */
		public static function elapsedMonths(dateA:Date, dateB:Date):Number 
		{
			return (elapsedDate(dateA, dateB).getUTCMonth() + 
				   (elapsedYears(dateA, dateB) * 12));
		}

		/**
		 * Returns the elapsed years between two given dates.
		 * 
		 * @param dateA The first date object, which should be "before" dateB.
		 * @param dateB The second date object, which should be "after" dateA.
		 */
		public static function elapsedYears(dateA:Date, dateB:Date):Number 
		{
			return (elapsedDate(dateA, dateB).getUTCFullYear() - 1970);
		}

		/**
		 * Adds a given amount of time to a given date and returns the new 
		 * valid date after the addition.
		 */
		public static function addTo(original:Date, years:Number = 0, 
								     months:Number = 0, days:Number = 0, 
								     hours:Number = 0, minutes:Number = 0, 
								     seconds:Number = 0, 
								     milliseconds:Number = 0):Date 
		{
			var newDate:Date = new Date(original.getTime());
			newDate.setFullYear(newDate.getFullYear() + years);
			newDate.setMonth(newDate.getMonth() + months);
			newDate.setDate(newDate.getDate() + days);
			newDate.setHours(newDate.getHours() + hours);
			newDate.setMinutes(newDate.getMinutes() + minutes);
			newDate.setSeconds(newDate.getSeconds() + seconds);
			newDate.setMilliseconds(newDate.getMilliseconds() + milliseconds);
			return newDate;
		}
	}
}
